优化拖拽上传逻辑:文件类型校验、图片预览与删除
概述
上一节完成了拖拽上传的样式定制,但存在一个 Bug:点击上传无法触发文件选择。本节修复此问题,并添加 before-upload 文件类型校验、图片预览和删除功能。
Bug 修复:点击上传无效
拖拽上传可以正常工作,但点击"点击上传"无响应。原因是自定义触发器插槽中缺少正确的文件类型限制和事件绑定。通过添加 accept 属性和 before-upload 钩子解决。
文件类型校验
before-upload 实现
使用 before-upload 钩子在校验文件类型,拒绝非图片文件:
<template>
<el-upload
v-bind="uploadAttrs"
:before-upload="handleBeforeUpload"
:on-success="handleSuccess"
:on-remove="handleRemove"
>
<!-- 自定义触发器 -->
</el-upload>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import type { UploadProps } from 'element-plus'
const handleBeforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
// 方式一:通过 type 属性判断
const isImage = rawFile.type.startsWith('image/')
if (!isImage) {
ElMessage.error('只能上传图片文件!')
return false
}
// 可选:文件大小校验
const isLt2M = rawFile.size / 1024 / 1024 < 2
if (!isLt2M) {
ElMessage.error('图片大小不能超过 2MB!')
return false
}
return true
}
</script>
vue
File 对象属性
| 属性 | 类型 | 说明 |
|---|---|---|
name | string | 文件名(含后缀) |
size | number | 文件大小(字节) |
type | string | MIME 类型(如 image/png) |
raw | File | 原始 File 对象 |
类型校验方式对比
| 方式 | 代码 | 优点 | 缺点 |
|---|---|---|---|
type 属性 | file.type.startsWith('image/') | 准确、覆盖所有图片格式 | 依赖浏览器识别 |
name 后缀 | file.name.endsWith('.jpg') | 简单直接 | 需逐个列举后缀 |
accept 属性 | accept="image/*" | 原生支持 | 仅限制选择器,不限制拖拽 |
推荐组合使用:accept 属性限制文件选择器 + before-upload 二次校验。
图片预览
上传成功后显示预览
<template>
<el-upload
:file-list="fileList"
:on-success="handleSuccess"
:on-preview="handlePreview"
list-type="picture"
>
<!-- 自定义触发器(无文件时显示) -->
<template v-if="fileList.length === 0">
<div class="upload-trigger">
<el-icon><upload-filled /></el-icon>
<div>拖拽上传或 <em>点击上传</em></div>
</div>
</template>
</el-upload>
<!-- 图片预览弹窗 -->
<el-dialog v-model="previewVisible" title="图片预览">
<img :src="previewUrl" style="width: 100%" />
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { UploadFile } from 'element-plus'
const fileList = ref<UploadFile[]>([])
const previewVisible = ref(false)
const previewUrl = ref('')
const handleSuccess = (response: any, uploadFile: UploadFile) => {
// 使用 URL.createObjectURL 生成本地预览
fileList.value = [{
name: uploadFile.name,
url: URL.createObjectURL(uploadFile.raw!),
}]
}
const handlePreview = (uploadFile: UploadFile) => {
previewUrl.value = uploadFile.url!
previewVisible.value = true
}
</script>
vue
删除功能
import { ElMessageBox } from 'element-plus'
const handleRemove: UploadProps['onRemove'] = (uploadFile) => {
ElMessageBox.confirm('确认删除该图片?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
// 释放 ObjectURL 内存
if (uploadFile.url) {
URL.revokeObjectURL(uploadFile.url)
}
fileList.value = fileList.value.filter(f => f.uid !== uploadFile.uid)
ElMessage.success('删除成功')
}).catch(() => {
// 取消删除
})
}
typescript
完整的属性配置
const uploadAttrs = {
action: '/api/upload',
drag: true,
multiple: false,
accept: 'image/*',
limit: 1,
'list-type': 'picture',
'before-upload': handleBeforeUpload,
'on-success': handleSuccess,
'on-remove': handleRemove,
'on-preview': handlePreview,
}
typescript
实践要点
before-upload返回false可阻止上传,同时显示错误提示accept="image/*"仅限制文件选择器中的显示类型,before-upload需二次校验URL.createObjectURL()生成的预览 URL 需在删除时调用URL.revokeObjectURL()释放内存- 上传成功后隐藏拖拽区域(通过
fileList.length判断),仅显示预览图 ElMessage需要从element-plus手动导入,不能直接使用全局注册的版本
↑